﻿namespace UnityEditor
{
    using System;
    using UnityEditorInternal;
    using UnityEngine;

    internal class OcclusionCullingWindow : EditorWindow
    {
        private float m_FarClipPlane = 1000f;
        private Mode m_Mode;
        private float m_NearClipPlane = 0.1f;
        private UnityEngine.Object[] m_Objects;
        private bool m_PreVis;
        private int m_PVSMemoryLimit = 0x989680;
        private Vector2 m_ScrollPosition = Vector2.zero;
        private string m_Warning;
        private static OcclusionCullingWindow ms_OcclusionCullingWindow;
        private static bool s_IsVisible;
        private static Styles s_Styles;

        private void AreaSelectionGUI()
        {
            GameObject[] objArray;
            bool flag = true;
            System.Type[] types = new System.Type[] { typeof(UnityEngine.Renderer), typeof(OcclusionArea) };
            System.Type type = SceneModeUtility.SearchBar(types);
            EditorGUILayout.Space();
            OcclusionArea[] selectedObjectsOfType = SceneModeUtility.GetSelectedObjectsOfType<OcclusionArea>(out objArray, new System.Type[0]);
            if (objArray.Length > 0)
            {
                flag = false;
                EditorGUILayout.MultiSelectionObjectTitleBar(selectedObjectsOfType);
                SerializedObject obj2 = new SerializedObject(selectedObjectsOfType);
                EditorGUILayout.PropertyField(obj2.FindProperty("m_IsViewVolume"), new GUILayoutOption[0]);
                obj2.ApplyModifiedProperties();
            }
            System.Type[] typeArray2 = new System.Type[] { typeof(MeshRenderer), typeof(SkinnedMeshRenderer) };
            UnityEngine.Renderer[] objects = SceneModeUtility.GetSelectedObjectsOfType<UnityEngine.Renderer>(out objArray, typeArray2);
            if (objArray.Length > 0)
            {
                flag = false;
                EditorGUILayout.MultiSelectionObjectTitleBar(objects);
                SerializedObject obj3 = new SerializedObject(objArray);
                SceneModeUtility.StaticFlagField("Occluder Static", obj3.FindProperty("m_StaticEditorFlags"), 2);
                SceneModeUtility.StaticFlagField("Occludee Static", obj3.FindProperty("m_StaticEditorFlags"), 0x10);
            }
            if (flag)
            {
                GUILayout.Label(s_Styles.emptyAreaSelection, EditorStyles.helpBox, new GUILayoutOption[0]);
                if (type == typeof(OcclusionArea))
                {
                    EditorGUIUtility.LookLikeControls(80f);
                    EditorGUILayout.Space();
                    EditorGUILayout.BeginHorizontal(new GUILayoutOption[0]);
                    EditorGUILayout.PrefixLabel("Create New");
                    GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.ExpandWidth(false) };
                    if (GUILayout.Button("Occlusion Area", EditorStyles.miniButton, options))
                    {
                        this.CreateNewArea();
                    }
                    EditorGUILayout.EndHorizontal();
                }
            }
        }

        private void Awake()
        {
            if (Camera.main != null)
            {
                this.m_NearClipPlane = Camera.main.nearClipPlane;
                this.m_FarClipPlane = Camera.main.farClipPlane;
            }
        }

        private static void BackgroundTaskStatusChanged()
        {
            if (ms_OcclusionCullingWindow != null)
            {
                ms_OcclusionCullingWindow.Repaint();
            }
        }

        private void BakeButtons()
        {
            float width = 95f;
            GUILayout.BeginHorizontal(new GUILayoutOption[0]);
            GUILayout.FlexibleSpace();
            bool flag = !EditorApplication.isPlayingOrWillChangePlaymode;
            GUI.enabled = (StaticOcclusionCulling.umbraDataSize != 0) && flag;
            GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.Width(width) };
            if (GUILayout.Button("Clear", options))
            {
                StaticOcclusionCulling.Clear();
            }
            GUI.enabled = flag;
            if (StaticOcclusionCulling.isRunning)
            {
                GUILayoutOption[] optionArray2 = new GUILayoutOption[] { GUILayout.Width(width) };
                if (GUILayout.Button("Cancel", optionArray2))
                {
                    StaticOcclusionCulling.Cancel();
                }
            }
            else
            {
                GUILayoutOption[] optionArray3 = new GUILayoutOption[] { GUILayout.Width(width) };
                if (GUILayout.Button("Bake", optionArray3))
                {
                    float viewCellSize = StaticOcclusionCullingVisualization.viewCellSize;
                    if (StaticOcclusionCullingVisualization.viewCellSize != viewCellSize)
                    {
                        StaticOcclusionCullingVisualization.viewCellSize = viewCellSize;
                    }
                    StaticOcclusionCullingVisualization.farClipPlane = this.m_FarClipPlane;
                    StaticOcclusionCullingVisualization.nearClipPlane = this.m_NearClipPlane;
                    StaticOcclusionCulling.GenerateInBackground(StaticOcclusionCullingVisualization.viewCellSize, this.m_NearClipPlane, this.m_FarClipPlane, this.m_PVSMemoryLimit, StaticOcclusionCullingVisualization.occlusionCullingMode);
                }
            }
            GUILayout.EndHorizontal();
            GUI.enabled = true;
        }

        private void BakeSettings()
        {
            StaticOcclusionCullingMode occlusionCullingMode = StaticOcclusionCullingVisualization.occlusionCullingMode;
            occlusionCullingMode = (StaticOcclusionCullingMode) EditorGUILayout.IntPopup(s_Styles.occlusionCullingMode, (int) occlusionCullingMode, s_Styles.cullingModeText, null, new GUILayoutOption[0]);
            StaticOcclusionCullingVisualization.occlusionCullingMode = occlusionCullingMode;
            GUILayout.Label(s_Styles.cullingModeText[(int) occlusionCullingMode].tooltip, EditorStyles.helpBox, new GUILayoutOption[0]);
            if (this.ShouldWarnManuallyPlacedPortals(occlusionCullingMode))
            {
                EditorGUILayout.HelpBox("Your scene contains manually placed portals. This is not supported with this technique.", MessageType.Warning);
            }
            float viewCellSize = StaticOcclusionCullingVisualization.viewCellSize;
            viewCellSize = Mathf.Max(EditorGUILayout.FloatField(s_Styles.viewCellSize, viewCellSize, new GUILayoutOption[0]), 1f);
            GUI.changed = false;
            this.m_NearClipPlane = EditorGUILayout.FloatField(s_Styles.nearClipPlane, this.m_NearClipPlane, new GUILayoutOption[0]);
            this.m_NearClipPlane = Mathf.Max(this.m_NearClipPlane, 0.1f);
            viewCellSize = Mathf.Max(viewCellSize, this.m_NearClipPlane);
            if (StaticOcclusionCullingVisualization.viewCellSize != viewCellSize)
            {
                StaticOcclusionCullingVisualization.viewCellSize = viewCellSize;
            }
            if (GUI.changed)
            {
                this.m_FarClipPlane = Mathf.Max(this.m_FarClipPlane, this.m_NearClipPlane);
            }
            GUI.changed = false;
            this.m_FarClipPlane = EditorGUILayout.FloatField(s_Styles.farClipPlane, this.m_FarClipPlane, new GUILayoutOption[0]);
            this.m_FarClipPlane = Mathf.Max(this.m_FarClipPlane, 0.001f);
            if (GUI.changed)
            {
                this.m_NearClipPlane = Mathf.Min(this.m_FarClipPlane, this.m_NearClipPlane);
            }
            GUI.enabled = (occlusionCullingMode == StaticOcclusionCullingMode.PVSOnly) || (occlusionCullingMode == StaticOcclusionCullingMode.PVSAndDynamicObjects);
            float kNumberW = EditorGUI.kNumberW;
            EditorGUI.kNumberW = 50f;
            GUILayout.BeginHorizontal(new GUILayoutOption[0]);
            this.m_PVSMemoryLimit = EditorGUILayout.IntSlider(s_Styles.pvsMemoryLimit, this.m_PVSMemoryLimit / 0x400, 0x30, 0x7270, new GUILayoutOption[0]) * 0x400;
            GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.Width(20f) };
            GUILayout.Label("KB", options);
            GUILayout.EndHorizontal();
            EditorGUI.kNumberW = kNumberW;
            GUI.enabled = true;
            StaticOcclusionCullingVisualization.farClipPlane = this.m_FarClipPlane;
            StaticOcclusionCullingVisualization.nearClipPlane = this.m_NearClipPlane;
        }

        private void CameraSelectionGUI()
        {
            System.Type[] types = new System.Type[] { typeof(Camera) };
            SceneModeUtility.SearchBar(types);
            EditorGUILayout.Space();
            Camera component = null;
            if (Selection.activeGameObject != null)
            {
                component = Selection.activeGameObject.GetComponent<Camera>();
            }
            if (component != null)
            {
                Camera[] objects = new Camera[] { component };
                EditorGUILayout.MultiSelectionObjectTitleBar(objects);
                EditorGUILayout.HelpBox(s_Styles.seeVisualizationInScene.text, MessageType.Info);
            }
            else
            {
                GUILayout.Label(s_Styles.emptyCameraSelection, EditorStyles.helpBox, new GUILayoutOption[0]);
            }
        }

        private OcclusionArea CreateNewArea()
        {
            GameObject obj2 = new GameObject("Occlusion Area");
            OcclusionArea area = obj2.AddComponent<OcclusionArea>();
            Selection.activeGameObject = obj2;
            return area;
        }

        private void DisplayControls(UnityEngine.Object target, SceneView sceneView)
        {
            if ((sceneView != null) && s_IsVisible)
            {
                bool flag2 = this.ShowModePopup(GUILayoutUtility.GetRect((float) 170f, (float) 18f));
                if (Event.current.type == EventType.Layout)
                {
                    this.m_Warning = string.Empty;
                    if (!flag2)
                    {
                        if (StaticOcclusionCullingVisualization.previewOcclucionCamera == null)
                        {
                            this.m_Warning = "No camera selected for occlusion preview.";
                        }
                        else if (!StaticOcclusionCullingVisualization.isPreviewOcclusionCullingCameraInPVS)
                        {
                            this.m_Warning = "Camera is not inside an Occlusion View Area.";
                        }
                    }
                }
                int num = 12;
                if (!string.IsNullOrEmpty(this.m_Warning))
                {
                    Rect position = GUILayoutUtility.GetRect(100f, (float) (num + 0x13));
                    position.x += EditorGUI.indent;
                    position.width -= EditorGUI.indent;
                    GUI.Label(position, this.m_Warning, EditorStyles.helpBox);
                }
                else
                {
                    Rect rect = GUILayoutUtility.GetRect(100f, (float) num);
                    rect.x += EditorGUI.indent;
                    rect.width -= EditorGUI.indent;
                    Rect rect3 = new Rect(rect.x, rect.y, rect.width, rect.height);
                    if (flag2)
                    {
                        EditorGUI.DrawLegend(rect3, Color.white, "View Volumes", StaticOcclusionCullingVisualization.showViewVolumes);
                    }
                    else
                    {
                        EditorGUI.DrawLegend(rect3, Color.white, "Camera Volume", StaticOcclusionCullingVisualization.showViewVolumes);
                    }
                    bool flag = GUI.Toggle(rect3, StaticOcclusionCullingVisualization.showViewVolumes, string.Empty, GUIStyle.none);
                    if (flag != StaticOcclusionCullingVisualization.showViewVolumes)
                    {
                        StaticOcclusionCullingVisualization.showViewVolumes = flag;
                        SceneView.RepaintAll();
                    }
                    if (!flag2)
                    {
                        rect = GUILayoutUtility.GetRect(100f, (float) num);
                        rect.x += EditorGUI.indent;
                        rect.width -= EditorGUI.indent;
                        rect3 = new Rect(rect.x, rect.y, rect.width, rect.height);
                        EditorGUI.DrawLegend(rect3, Color.green, "Visibility Lines", StaticOcclusionCullingVisualization.showVisibilityLines);
                        flag = GUI.Toggle(rect3, StaticOcclusionCullingVisualization.showVisibilityLines, string.Empty, GUIStyle.none);
                        if (flag != StaticOcclusionCullingVisualization.showVisibilityLines)
                        {
                            StaticOcclusionCullingVisualization.showVisibilityLines = flag;
                            SceneView.RepaintAll();
                        }
                        rect = GUILayoutUtility.GetRect(100f, (float) num);
                        rect.x += EditorGUI.indent;
                        rect.width -= EditorGUI.indent;
                        rect3 = new Rect(rect.x, rect.y, rect.width, rect.height);
                        EditorGUI.DrawLegend(rect3, Color.grey, "Portals", StaticOcclusionCullingVisualization.showPortals);
                        flag = GUI.Toggle(rect3, StaticOcclusionCullingVisualization.showPortals, string.Empty, GUIStyle.none);
                        if (flag != StaticOcclusionCullingVisualization.showPortals)
                        {
                            StaticOcclusionCullingVisualization.showPortals = flag;
                            SceneView.RepaintAll();
                        }
                    }
                    EditorGUIUtility.LookLikeControls();
                    if (!flag2)
                    {
                        flag = GUILayout.Toggle(StaticOcclusionCullingVisualization.showGeometryCulling, "Occlusion culling", new GUILayoutOption[0]);
                        if (flag != StaticOcclusionCullingVisualization.showGeometryCulling)
                        {
                            StaticOcclusionCullingVisualization.showGeometryCulling = flag;
                            SceneView.RepaintAll();
                        }
                    }
                }
            }
        }

        [UnityEditor.MenuItem("Window/Occlusion Culling", false, 0x833)]
        private static void GenerateWindow()
        {
            if (Application.HasProLicense())
            {
                System.Type[] desiredDockNextTo = new System.Type[] { typeof(InspectorWindow) };
                OcclusionCullingWindow window = EditorWindow.GetWindow<OcclusionCullingWindow>(desiredDockNextTo);
                window.title = "Occlusion";
                window.minSize = new Vector2(300f, 250f);
            }
            else
            {
                Debug.LogError("Occlusion Culling is only supported in Unity Pro.");
            }
        }

        private void ModeToggle()
        {
            this.m_Mode = (Mode) GUILayout.Toolbar((int) this.m_Mode, s_Styles.ModeToggles, "LargeButton", new GUILayoutOption[0]);
            if (GUI.changed)
            {
                if ((this.m_Mode == Mode.Visualization) && (StaticOcclusionCulling.umbraDataSize > 0))
                {
                    StaticOcclusionCullingVisualization.showPreVisualization = false;
                }
                else
                {
                    StaticOcclusionCullingVisualization.showPreVisualization = true;
                }
                SceneView.RepaintAll();
            }
        }

        private void OnBecameInvisible()
        {
            s_IsVisible = false;
            SceneView.onSceneGUIDelegate = (SceneView.OnSceneFunc) Delegate.Remove(SceneView.onSceneGUIDelegate, new SceneView.OnSceneFunc(this.OnSceneViewGUI));
            StaticOcclusionCullingVisualization.showOcclusionCulling = false;
            SceneView.RepaintAll();
        }

        private void OnBecameVisible()
        {
            if (!s_IsVisible)
            {
                s_IsVisible = true;
                SceneView.onSceneGUIDelegate = (SceneView.OnSceneFunc) Delegate.Combine(SceneView.onSceneGUIDelegate, new SceneView.OnSceneFunc(this.OnSceneViewGUI));
                StaticOcclusionCullingVisualization.showOcclusionCulling = true;
                SceneView.RepaintAll();
            }
        }

        private void OnDidOpenScene()
        {
            base.Repaint();
        }

        private void OnDisable()
        {
            ms_OcclusionCullingWindow = null;
            EditorApplication.searchChanged = (EditorApplication.CallbackFunction) Delegate.Remove(EditorApplication.searchChanged, new EditorApplication.CallbackFunction(this.Repaint));
        }

        private void OnEnable()
        {
            ms_OcclusionCullingWindow = this;
            base.autoRepaintOnSceneChange = true;
            EditorApplication.searchChanged = (EditorApplication.CallbackFunction) Delegate.Combine(EditorApplication.searchChanged, new EditorApplication.CallbackFunction(this.Repaint));
            base.Repaint();
        }

        private void OnGUI()
        {
            if (s_Styles == null)
            {
                s_Styles = new Styles();
            }
            if ((this.m_Mode != Mode.Visualization) && !StaticOcclusionCullingVisualization.showPreVisualization)
            {
                this.m_Mode = Mode.Visualization;
            }
            EditorGUILayout.Space();
            this.ModeToggle();
            EditorGUILayout.Space();
            this.m_ScrollPosition = EditorGUILayout.BeginScrollView(this.m_ScrollPosition, new GUILayoutOption[0]);
            switch (this.m_Mode)
            {
                case Mode.AreaSettings:
                    this.AreaSelectionGUI();
                    break;

                case Mode.BakeSettings:
                    this.BakeSettings();
                    break;

                case Mode.Visualization:
                    if (StaticOcclusionCulling.umbraDataSize <= 0)
                    {
                        GUILayout.Label(s_Styles.noOcclusionData, EditorStyles.helpBox, new GUILayoutOption[0]);
                        break;
                    }
                    this.CameraSelectionGUI();
                    GUILayout.FlexibleSpace();
                    GUILayout.Label(s_Styles.visualizationNote, EditorStyles.helpBox, new GUILayoutOption[0]);
                    break;
            }
            EditorGUILayout.EndScrollView();
            EditorGUILayout.Space();
            this.BakeButtons();
            EditorGUILayout.Space();
            this.SummaryGUI();
        }

        public void OnSceneViewGUI(SceneView sceneView)
        {
            if (s_IsVisible)
            {
                SceneViewOverlay.Window(new GUIContent("Occlusion Culling"), new SceneViewOverlay.WindowFunction(this.DisplayControls), 100, SceneViewOverlay.WindowDisplayOption.OneWindowPerTarget);
            }
        }

        private void OnSelectionChange()
        {
            if ((this.m_Mode == Mode.AreaSettings) || (this.m_Mode == Mode.Visualization))
            {
                base.Repaint();
            }
        }

        private void SetShowVolumeCulling()
        {
            StaticOcclusionCullingVisualization.showPreVisualization = false;
            this.m_Mode = Mode.Visualization;
            if (ms_OcclusionCullingWindow != null)
            {
                ms_OcclusionCullingWindow.Repaint();
            }
            SceneView.RepaintAll();
        }

        private void SetShowVolumePreVis()
        {
            StaticOcclusionCullingVisualization.showPreVisualization = true;
            if (this.m_Mode == Mode.Visualization)
            {
                this.m_Mode = Mode.AreaSettings;
            }
            if (ms_OcclusionCullingWindow != null)
            {
                ms_OcclusionCullingWindow.Repaint();
            }
            SceneView.RepaintAll();
        }

        [UnityEditor.MenuItem("Window/Occlusion Culling", true, 0x833)]
        public static bool SetupWindowValidate()
        {
            return InternalEditorUtility.HasPro();
        }

        private bool ShouldWarnManuallyPlacedPortals(StaticOcclusionCullingMode mode)
        {
            if ((mode != StaticOcclusionCullingMode.PVSOnly) && (mode != StaticOcclusionCullingMode.PVSAndDynamicObjects))
            {
                return false;
            }
            return StaticOcclusionCulling.doesSceneHaveManualPortals;
        }

        private bool ShowModePopup(Rect popupRect)
        {
            int umbraDataSize = StaticOcclusionCulling.umbraDataSize;
            if (this.m_PreVis != StaticOcclusionCullingVisualization.showPreVisualization)
            {
                SceneView.RepaintAll();
            }
            if (Event.current.type == EventType.Layout)
            {
                this.m_PreVis = StaticOcclusionCullingVisualization.showPreVisualization;
            }
            string[] strArray = new string[] { "Edit", "Visualize" };
            int index = !this.m_PreVis ? 1 : 0;
            if (EditorGUI.ButtonMouseDown(popupRect, new GUIContent(strArray[index]), FocusType.Passive, EditorStyles.popup))
            {
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent(strArray[0]), index == 0, new GenericMenu.MenuFunction(this.SetShowVolumePreVis));
                if (umbraDataSize > 0)
                {
                    menu.AddItem(new GUIContent(strArray[1]), index == 1, new GenericMenu.MenuFunction(this.SetShowVolumeCulling));
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent(strArray[1]));
                }
                menu.Popup(popupRect, index);
            }
            return this.m_PreVis;
        }

        private void SummaryGUI()
        {
            GUILayout.BeginVertical(EditorStyles.helpBox, new GUILayoutOption[0]);
            if (!Application.HasAdvancedLicense())
            {
                EditorGUILayout.HelpBox(BuildPipeline.GetBuildTargetAdvancedLicenseName(EditorUserBuildSettings.activeBuildTarget) + " is required for Occlusion Culling on " + BuildPipeline.GetBuildTargetGroupName(EditorUserBuildSettings.activeBuildTarget), MessageType.Warning);
            }
            if (StaticOcclusionCulling.umbraDataSize == 0)
            {
                GUILayout.Label(s_Styles.noOcclusionData, s_Styles.labelStyle, new GUILayoutOption[0]);
            }
            else
            {
                GUILayout.Label("Last bake:", s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.BeginHorizontal(new GUILayoutOption[0]);
                GUILayout.BeginVertical(new GUILayoutOption[0]);
                GUILayout.Label("Data size on disk ", s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.Label("Static PVS data size ", s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.Label("Dynamic culling data size ", s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.EndVertical();
                GUILayout.BeginVertical(new GUILayoutOption[0]);
                GUILayout.Label(EditorUtility.FormatBytes(StaticOcclusionCulling.umbraDataSize), s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.Label(EditorUtility.FormatBytes(StaticOcclusionCulling.staticObjectDataSize), s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.Label(EditorUtility.FormatBytes(StaticOcclusionCulling.dynamicObjectDataSize), s_Styles.labelStyle, new GUILayoutOption[0]);
                GUILayout.EndVertical();
                GUILayout.EndHorizontal();
            }
            GUILayout.EndVertical();
        }

        private enum Mode
        {
            AreaSettings,
            BakeSettings,
            Visualization
        }

        private class Styles
        {
            public GUIContent[] cullingModeText = EditorGUIUtility.GetTextContentsForEnum(typeof(StaticOcclusionCullingMode));
            public GUIContent emptyAreaSelection = new GUIContent("Select a Mesh Renderer or an Occlusion Area from the scene.");
            public GUIContent emptyCameraSelection = new GUIContent("Select a Camera from the scene.");
            public GUIContent farClipPlane = EditorGUIUtility.TextContent("OcclusionCullingWindow.FarClipPlane");
            public GUIStyle labelStyle = EditorStyles.wordWrappedMiniLabel;
            public GUIContent[] ModeToggles = new GUIContent[] { new GUIContent("Object"), new GUIContent("Bake"), new GUIContent("Visualization") };
            public GUIContent nearClipPlane = EditorGUIUtility.TextContent("OcclusionCullingWindow.NearClipPlane");
            public GUIContent noOcclusionData = new GUIContent("No occlusion data has been baked.");
            public GUIContent occlusionCullingMode = EditorGUIUtility.TextContent("OcclusionCullingWindow.OcclusionCullingMode");
            public GUIContent pvsMemoryLimit = EditorGUIUtility.TextContent("OcclusionCullingWindow.PVSMemoryLimit");
            public GUIContent seeVisualizationInScene = new GUIContent("See the occlusion culling visualization in the Scene View based on the selected Camera.");
            public GUIContent viewCellSize = EditorGUIUtility.TextContent("OcclusionCullingWindow.ViewCellSize");
            public GUIContent visualizationNote = new GUIContent("The visualization may not correspond to current bake settings and Occlusion Area placements if they have been changed since last bake.");
        }
    }
}

